package threadlocal.reference;

import org.junit.Test;

import java.lang.ref.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * 四种引用测试
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/08/25 下午 02:58
 */
public class ReferenceTest {

    /**
     * 测试强引用 (设置虚拟机参数为 -Xms10m -Xmx10m)
     * 即使内存不足obj指向的对象也不会被回收
     */
    @Test
    public void testReference() {
        MyObject obj = new MyObject();
        //主动触发垃圾回收
        System.gc();
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc after :" + obj);

        try {
            Byte[] bytes = new Byte[20 * 1024 * 1024];
        } finally {
            System.out.println("gc after :" + obj);
        }
    }

    /**
     * 测试软引用 (设置虚拟机参数为 -Xms10m -Xmx10m)
     * <p>
     * 内存充足时指向的对象不会被回收
     * 内存不足obj指向的对象也会被回收
     */
    @Test
    public void testSoftReference() {
        SoftReference<MyObject> obj = new SoftReference<>(new MyObject());
        //主动触发垃圾回收
        System.gc();
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc after :" + obj.get());

        try {
            Byte[] bytes = new Byte[20 * 1024 * 1024];
        } finally {
            System.out.println("gc after :" + obj.get());
        }
    }

    /**
     * 测试弱引用 (设置虚拟机参数为 -Xms10m -Xmx10m)
     * <p>
     * 执行GC就会被回收
     */
    @Test
    public void testWeakReference() {
        WeakReference<MyObject> obj = new WeakReference<>(new MyObject());
        //主动触发垃圾回收
        System.gc();
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //输出null ，被gc回收了
        System.out.println("gc after :" + obj.get());

//        try {
//            Byte[] bytes = new Byte[20 * 1024 * 1024];
//        } finally {
//            System.out.println("gc after :" + obj.get());
//        }
    }


    /**
     * 测试虚引用 (设置虚拟机参数为 -Xms10m -Xmx10m)
     * <p>
     * 当内存不足时，虚引用对象被回收，并且虚引用对象会进入引用队列中。
     */
    @Test
    public void testPhantomReference() throws InterruptedException {
        ReferenceQueue<MyObject> queue = new ReferenceQueue<>();
        PhantomReference<MyObject> obj = new PhantomReference<>(new MyObject(), queue);
        PhantomReference<MyObject> obj2 = new PhantomReference<>(new MyObject(), queue);
        PhantomReference<MyObject> obj3 = new PhantomReference<>(new MyObject(), queue);

        List<Byte[]> list = new ArrayList<>();
        CountDownLatch latch = new CountDownLatch(1);
        new Thread(() -> {
            try {
                while (true) {
                    list.add(new Byte[1024 * 1024]);
                    System.out.println("obj:" + obj.get());
                    try {
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } finally {
                latch.countDown();
            }
        }
        ).start();

        new Thread(() -> {
            boolean x = true;
            while (true) {
                Reference<? extends MyObject> reference = queue.poll();
                if (reference != null) {
                    System.out.println("元素进入引用队列");
                    x = false;
                } else if (false == x) {
                    return;
                }
            }
        }).start();

        latch.await();
    }
}

class MyObject {
    // 重写finalize(), 当对象不可达时，该对象会被gc清理， finalize()方法会被调用。
    @Override
    protected void finalize() throws Throwable {
        System.out.println("触发finalize。。。");
    }
}

